package com.kvn.plugin.tools;

import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.intellij.database.model.DasColumn;
import com.intellij.database.psi.DbTable;
import com.intellij.database.util.DasUtil;
import com.intellij.util.containers.JBIterable;
import com.kvn.plugin.KvnPluginContext;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 表信息工具类
 *
 * @author makejava
 * @version 1.0.0
 * @since 2018/07/17 13:10
 */
public class TableInfoUtils {
    private volatile static TableInfoUtils tableInfoUtils;

    /**
     * 单例模式
     */
    public static TableInfoUtils getInstance() {
        if (tableInfoUtils == null) {
            synchronized (TableInfoUtils.class) {
                if (tableInfoUtils == null) {
                    tableInfoUtils = new TableInfoUtils();
                }
            }
        }
        return tableInfoUtils;
    }

    /**
     * 私有构造方法
     */
    private TableInfoUtils() {
    }

    /**
     * 缓存数据工具类
     */
    private KvnPluginContext kvnPluginContext = KvnPluginContext.instance();
    /**
     * jackson格式化工具
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 文件工具类
     */
    private FileUtils fileUtils = FileUtils.getInstance();

    /**
     * 保存的相对路径
     */
    private static final String SAVE_PATH = "/.idea/EasyCodeConfig";

    private StrategyConfig strategyConfig;
    private ITypeConvert typeConvert = new MySqlTypeConvert();

    /**
     * 处理方法，默认加载配置
     *
     * @param dbTables 数据库表信息
     * @return 表信息
     */
    public List<TableInfo> handler(Collection<DbTable> dbTables) {
        return handler(dbTables, true);
    }

    /**
     * 数据库表处理器
     *
     * @param dbTables   数据库表
     * @param loadConfig 是否加载配置信息
     * @return 处理结果
     */
    private List<TableInfo> handler(Collection<DbTable> dbTables, boolean loadConfig) {
        String[] tableNames = (String[]) Collections2.transform(dbTables, new Function<DbTable, String>() {
            public String apply(DbTable dbTable) {
                return dbTable.getName();
            }
        }).toArray();
        // FIXME 设置StrategyConfig，后面可以做与配置页面
        strategyConfig = new StrategyConfig()
                .setCapitalMode(true)
                .setEntityLombokModel(true) // lombok支持
                .setDbColumnUnderline(true)
                .setNaming(NamingStrategy.underline_to_camel)
//                .setTablePrefix("ts_")
                .setInclude(tableNames);//修改替换成你需要的表名，多个表名传数组


        List<TableInfo> result = new ArrayList<>();
        dbTables.forEach(dbTable -> {
            result.add(convertTableFields(dbTable, strategyConfig.getNaming()));
        });
        return result;
    }

    /**
     * <p>
     * 将字段信息与表信息关联
     * </p>
     *
     * @param dbTable 表信息
     * @param strategy  命名策略
     * @return
     * @see com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder#convertTableFields
     */
    private TableInfo convertTableFields(DbTable dbTable, NamingStrategy strategy) {
        TableInfo tableInfo = new TableInfo();
        tableInfo.setName(dbTable.getName());
        tableInfo.setComment(dbTable.getComment());


        List<TableField> fieldList = new ArrayList<>();
        List<TableField> commonFieldList = new ArrayList<>();


        // 处理所有列
        JBIterable<? extends DasColumn> columns = DasUtil.getColumns(dbTable);
        for (DasColumn column : columns) {
            TableField field = new TableField();
            field.setKeyFlag(DasUtil.isPrimary(column)); // 是否为主键
            field.setKeyIdentityFlag(DasUtil.isAutoGenerated(column)); // 主键是否为自增类型
            // 处理其它信息
            field.setName(column.getName());
            field.setType(column.getDataType().typeName);
            field.setPropertyName(strategyConfig, processName(field.getName(), strategy));
            field.setColumnType(typeConvert.processTypeConvert(field.getType()));
            field.setComment(column.getComment());
            if (strategyConfig.includeSuperEntityColumns(field.getName())) {
                // 跳过公共字段
                commonFieldList.add(field);
                continue;
            }
            // 填充逻辑判断
            List<TableFill> tableFillList = strategyConfig.getTableFillList();
            if (null != tableFillList) {
                for (TableFill tableFill : tableFillList) {
                    if (tableFill.getFieldName().equals(field.getName())) {
                        field.setFill(tableFill.getFieldFill().name());
                        break;
                    }
                }
            }
            fieldList.add(field);
        }
        tableInfo.setFields(fieldList);
        tableInfo.setCommonFields(commonFieldList);
        return tableInfo;
    }


    /**
     * <p>
     * 处理字段名称
     * </p>
     *
     * @return 根据策略返回处理后的名称
     */
    private String processName(String name, NamingStrategy strategy) {
        return processName(name, strategy, this.strategyConfig.getFieldPrefix());
    }

    /**
     * <p>
     * 处理表/字段名称
     * </p>
     *
     * @param name
     * @param strategy
     * @param prefix
     * @return 根据策略返回处理后的名称
     */
    private String processName(String name, NamingStrategy strategy, String[] prefix) {
        boolean removePrefix = false;
        if (prefix != null && prefix.length >= 1) {
            removePrefix = true;
        }
        String propertyName;
        if (removePrefix) {
            if (strategy == NamingStrategy.underline_to_camel) {
                // 删除前缀、下划线转驼峰
                propertyName = NamingStrategy.removePrefixAndCamel(name, prefix);
            } else {
                // 删除前缀
                propertyName = NamingStrategy.removePrefix(name, prefix);
            }
        } else if (strategy == NamingStrategy.underline_to_camel) {
            // 下划线转驼峰
            propertyName = NamingStrategy.underlineToCamel(name);
        } else {
            // 不处理
            propertyName = name;
        }
        return propertyName;
    }






    /**
     * 读取配置文件
     * @param dbTable 表对象信息
     * @return 读取到的配置信息
     */
    private TableInfo readConfig(DbTable dbTable) {
        // 获取保存的目录
        String path = kvnPluginContext.getProject().getBasePath() + SAVE_PATH;
        File dir = new File(path);
        if (!dir.exists()) {
            if (!dir.mkdir()) {
                return null;
            }
        }
        // 获取保存的文件
        String schemaName = DasUtil.getSchema(dbTable);
        String fileName = schemaName + "-" + dbTable.getName() + ".json";
        File file = new File(dir, fileName);
        if (!file.exists()) {
            return null;
        }
        // 读取并解析文件
        return parser(fileUtils.read(file));
    }

    /**
     * 对象还原
     * @param str 原始JSON字符串
     * @return 解析结果
     */
    private TableInfo parser(String str) {
        try {
            return objectMapper.readValue(str, TableInfo.class);
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, "读取配置失败，JSON反序列化异常。", "温馨提示", JOptionPane.PLAIN_MESSAGE);
        }
        return null;
    }
}
